package cn.iocoder.yudao.module.lowcode.service.datasource.impl;

import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.lowcode.controller.admin.datasource.vo.DatasourceConfigPageReqVO;
import cn.iocoder.yudao.module.lowcode.controller.admin.datasource.vo.DatasourceConfigSaveReqVO;
import cn.iocoder.yudao.module.lowcode.controller.admin.datasource.vo.DatasourceConnectionTestRespVO;
import cn.iocoder.yudao.module.lowcode.controller.admin.datasource.vo.DatasourceHealthRespVO;
import cn.iocoder.yudao.module.lowcode.dal.dataobject.datasource.DatasourceConfigDO;
import cn.iocoder.yudao.module.lowcode.dal.mysql.datasource.DatasourceConfigMapper;
import cn.iocoder.yudao.module.lowcode.service.datasource.DatasourceConfigService;
import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.sql.Connection;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.lowcode.enums.ErrorCodeConstants.DATASOURCE_CONFIG_NAME_DUPLICATE;
import static cn.iocoder.yudao.module.lowcode.enums.ErrorCodeConstants.DATASOURCE_CONFIG_NOT_EXISTS;

/**
 * 数据源配置 Service 实现类
 *
 * @author YuDao
 */
@Service
@Validated
@Slf4j
public class DatasourceConfigServiceImpl implements DatasourceConfigService {

    @Resource
    private DatasourceConfigMapper datasourceConfigMapper;



    @Override
    public Long createDatasourceConfig(@Valid DatasourceConfigSaveReqVO createReqVO) {
        // 校验数据源名称唯一
        validateDatasourceNameUnique(null, createReqVO.getName());
        
        // 插入
        DatasourceConfigDO datasourceConfig = BeanUtils.toBean(createReqVO, DatasourceConfigDO.class);
        datasourceConfigMapper.insert(datasourceConfig);
        // 返回
        return datasourceConfig.getId();
    }

    @Override
    public void updateDatasourceConfig(@Valid DatasourceConfigSaveReqVO updateReqVO) {
        // 校验存在
        validateDatasourceConfigExists(updateReqVO.getId());
        // 校验数据源名称唯一
        validateDatasourceNameUnique(updateReqVO.getId(), updateReqVO.getName());
        
        // 更新
        DatasourceConfigDO updateObj = BeanUtils.toBean(updateReqVO, DatasourceConfigDO.class);
        datasourceConfigMapper.updateById(updateObj);
        
    }

    @Override
    public void deleteDatasourceConfig(Long id) {
        // 校验存在
        DatasourceConfigDO config = validateDatasourceConfigExists(id);
        
        // 检查是否有依赖的脚本或其他组件在使用此数据源
        // 这里可以添加更复杂的依赖检查逻辑
        // validateDatasourceNotInUse(id);
        
        // 删除前记录日志
        log.info("删除数据源配置: id={}, name={}", id, config.getName());
        
        // 删除
        datasourceConfigMapper.deleteById(id);
    }

    private DatasourceConfigDO validateDatasourceConfigExists(Long id) {
        DatasourceConfigDO config = datasourceConfigMapper.selectById(id);
        if (config == null) {
            throw exception(DATASOURCE_CONFIG_NOT_EXISTS);
        }
        return config;
    }

    private void validateDatasourceNameUnique(Long id, String name) {
        DatasourceConfigDO datasourceConfig = datasourceConfigMapper.selectByName(name);
        if (datasourceConfig == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的数据源
        if (id == null) {
            throw exception(DATASOURCE_CONFIG_NAME_DUPLICATE);
        }
        if (!datasourceConfig.getId().equals(id)) {
            throw exception(DATASOURCE_CONFIG_NAME_DUPLICATE);
        }
    }

    @Override
    public DatasourceConfigDO getDatasourceConfig(Long id) {
        return datasourceConfigMapper.selectById(id);
    }

    @Override
    public PageResult<DatasourceConfigDO> getDatasourceConfigPage(DatasourceConfigPageReqVO pageReqVO) {
        return datasourceConfigMapper.selectPage(pageReqVO);
    }

    @Override
    public DatasourceConnectionTestRespVO testConnection(@Valid DatasourceConfigSaveReqVO testReqVO) {
        long startTime = System.currentTimeMillis();
        
        DruidDataSource dataSource = null;
        try {
            // 创建测试数据源
            dataSource = new DruidDataSource();
            dataSource.setUrl(testReqVO.getUrl());
            dataSource.setUsername(testReqVO.getUsername());
            if(testReqVO.getPassword() == null){
                DatasourceConfigDO datasourceConfigDO = datasourceConfigMapper.selectOne(DatasourceConfigDO::getName, testReqVO.getName());
                dataSource.setPassword(datasourceConfigDO.getPassword());
            }
            dataSource.setDriverClassName(testReqVO.getDriverClassName());
            dataSource.setInitialSize(testReqVO.getInitialSize() != null ? testReqVO.getInitialSize() : 1);
            dataSource.setMaxActive(testReqVO.getMaxActive() != null ? testReqVO.getMaxActive() : 1);
            dataSource.setMinIdle(testReqVO.getMinIdle() != null ? testReqVO.getMinIdle() : 1);
            dataSource.setMaxWait(5000);
            dataSource.setTestWhileIdle(true);
            if (testReqVO.getTestQuery() != null) {
                dataSource.setValidationQuery(testReqVO.getTestQuery());
            }
            
            // 初始化数据源
            dataSource.init();
            
            // 获取连接测试
            try (Connection connection = dataSource.getConnection()) {
                // 测试连接是否有效
                if (connection.isValid(5)) {
                    long responseTime = System.currentTimeMillis() - startTime;
                    return DatasourceConnectionTestRespVO.success(responseTime, "数据源连接测试成功");
                } else {
                    return DatasourceConnectionTestRespVO.failure("连接无效", "连接有效性检查失败");
                }
            }
            
        } catch (Exception e) {
            log.error("数据源连接测试失败", e);
            return DatasourceConnectionTestRespVO.failure("连接测试失败", e.getMessage());
        } finally {
            if (dataSource != null) {
                try {
                    dataSource.close();
                } catch (Exception closeException) {
                    log.warn("关闭测试数据源时发生异常", closeException);
                }
            }
        }
    }

    @Override
    public DatasourceHealthRespVO getHealth(Long id) {
        DatasourceConfigDO config = getDatasourceConfig(id);
        if (config == null || !CommonStatusEnum.ENABLE.getStatus().equals(config.getStatus())) {
            DatasourceHealthRespVO resp = new DatasourceHealthRespVO();
            resp.setHealthy(false);
            resp.setDetails("数据源不存在或已禁用");
            resp.setLastCheckTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            return resp;
        }

        // 实现真实的健康检查
        DatasourceHealthRespVO resp = new DatasourceHealthRespVO();
        
        // 测试数据源连接
        DatasourceConfigSaveReqVO testConfig = new DatasourceConfigSaveReqVO();
        testConfig.setUrl(config.getUrl());
        testConfig.setUsername(config.getUsername());
        testConfig.setPassword(config.getPassword());
        testConfig.setDriverClassName(config.getDriverClassName());
        testConfig.setMaxActive(config.getMaxActive());
        testConfig.setTestQuery(config.getTestQuery());
        
        DatasourceConnectionTestRespVO testResult = testConnection(testConfig);
        
        resp.setHealthy(Boolean.TRUE.equals(testResult.getSuccess()));
        resp.setMaxConnections(config.getMaxActive() != null ? config.getMaxActive() : 8);
        resp.setDetails(Boolean.TRUE.equals(testResult.getSuccess()) ? 
            "数据源连接正常，响应时间: " + testResult.getResponseTime() + "ms" : 
            "数据源连接异常: " + testResult.getMessage());
        resp.setLastCheckTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        
        // 模拟连接池状态 (实际项目中应该从真实连接池获取)
        if (Boolean.TRUE.equals(testResult.getSuccess())) {
            resp.setActiveConnections(2); // 模拟活跃连接数
            resp.setIdleConnections(config.getMinIdle() != null ? config.getMinIdle() : 1);
        } else {
            resp.setActiveConnections(0);
            resp.setIdleConnections(0);
        }
        
        return resp;
    }

    @Override
    @Transactional
    public void updateDatasourceStatus(Long id, Integer status) {
        // 校验存在
        DatasourceConfigDO config = validateDatasourceConfigExists(id);
        
        // 记录状态变更日志
        log.info("更新数据源状态: id={}, name={}, oldStatus={}, newStatus={}", 
            id, config.getName(), config.getStatus(), status);
        
        // 更新状态
        DatasourceConfigDO updateObj = new DatasourceConfigDO();
        updateObj.setId(id);
        updateObj.setStatus(status);
        datasourceConfigMapper.updateById(updateObj);
    }

    @Override
    public List<String> getSupportedDatabaseTypes() {
        return Arrays.asList("mysql", "postgresql", "oracle", "sqlserver", "h2");
    }

    @Override
    public DatasourceConfigDO getDatasourceByName(String name) {
        return datasourceConfigMapper.selectByName(name);
    }

    @Override
    public List<DatasourceConfigDO> getActiveDataSourceList() {
        return datasourceConfigMapper.selectActiveDataSources();
    }
}